package com.winit.need.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.winit.common.base.bean.ExecuteResult;
import com.winit.common.base.web.BaseController;
import com.winit.common.util.DateGenerator;
import com.winit.commons.upush.SendEmail;
import com.winit.commons.util.SeqGenerate;
import com.winit.issue.manager.IssueManager;
import com.winit.issue.model.Issue;
import com.winit.need.mapper.NeedMapper;
import com.winit.need.mapper.NeedPageMapper;
import com.winit.need.mapper.NeedPdmMapper;
import com.winit.need.model.Need;
import com.winit.need.model.NeedPage;
import com.winit.need.model.NeedPdm;
import com.winit.need.service.NeedService;
import com.winit.need.util.NeedUtil;
import com.winit.projectPlan.model.ProjectPlan;
import com.winit.projectPlan.repository.ProjectPlanRepository;
import com.winit.requirement.manager.BrdRequirementManager;
import com.winit.requirement.model.BrdRequirement;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


@Service(value = "needService")
public class NeedServiceImpl implements NeedService {
    private static Logger log = LoggerFactory.getLogger(NeedService.class);


    @Value("${overtime_day}")
    protected Integer overtimeDay;

    @Autowired
    private NeedMapper needMapper;

    @Autowired
    private NeedPageMapper needPageMapper;

    @Autowired
    private NeedPdmMapper needPdmMapper;

    @Autowired
    private IssueManager issueManager;

    @Autowired
    BrdRequirementManager brdRequirementManager;

    @Autowired
    ProjectPlanRepository projectPlanRepository;


    @Override
    public Need selectByPrimaryKey(String reqId) {
        return needMapper.selectByPrimaryKey(reqId);
    }

    @Override
    public ExecuteResult<Need> saveNeed(Need need) {
        ExecuteResult<Need> executeResult = new ExecuteResult();
        need.setId(SeqGenerate.createId("NEED"));
        need.setCreateTime(new Date());
        need.setStatus("NO_ACCEPT");
        need.setAdmissibilityStatus("NO_ACCEPT");
        need.setStatusTimes(NeedUtil.dealStatusTime(null, "NO_ACCEPT"));
        //未受理
        needMapper.insertSelective(need);
        if (null != need.getNeedPage() && need.getNeedPage().size() != 0) {
            for (NeedPage page : need.getNeedPage()) {
                page.setId(SeqGenerate.createId("NP"));
                page.setNeedId(need.getId());
            }
            needPageMapper.insertByBatch(need.getNeedPage());
        }
        if (need.getNeedPdm() != null && need.getNeedPdm().size() != 0) {
            for (NeedPdm needPdm : need.getNeedPdm()) {
                needPdm.setNeedId(need.getId());
            }
            needPdmMapper.insertByBatch(need.getNeedPdm());
        }
        executeResult.setData(need);
        return executeResult;
    }

    @Override
    public ExecuteResult<Need> updateNeed(Need need) {
        ExecuteResult<Need> executeResult = new ExecuteResult();

        Need oldNeed = needMapper.selectByPrimaryKey(need.getId());
        if ("ONLINE".equals(oldNeed.getStatus()) || "CLOSED".equals(oldNeed.getStatus())) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("当前需求已经上线或结束禁止编辑");
            return executeResult;
        }
//        if("DEVING".equals(oldNeed.getStatus()) || "INTEGRATIONING".equals(oldNeed.getStatus()) || "PLANS".equals(oldNeed.getStatus()) || "LATED".equals(oldNeed.getStatus())){
//            executeResult.setCode(BaseController.REQUEST_ERROR);
//            executeResult.setDesc("当前需求已经立项禁止编辑");
//            return executeResult;
//        }
        //发送消息
        this.sendNeedMsg(need, oldNeed);
        //处理需求取消回退状态
//        if ("1".equals(oldNeed.getIsFallback()) && "0".equals(need.getIsFallback())) {
//            if (need.getNeedPdm().size() > 0) {
//                need.setStatus("CONFIRM");
//            }else {
//                need.setStatus("NO_ACCEPT");
//            }
//            need.setFallbackReason("");
//        }
        if (!oldNeed.getStatus().equals(need.getStatus())) {
            need.setStatusTimes(NeedUtil.dealStatusTime(oldNeed.getStatusTimes(), need.getStatus()));
        }
        needPageMapper.deleteByNeedId(need.getId());
        if (need.getNeedPage() != null && need.getNeedPage().size() != 0) {
            for (NeedPage page : need.getNeedPage()) {
                page.setId(SeqGenerate.createId("NP"));
                page.setNeedId(need.getId());
            }
            needPageMapper.insertByBatch(need.getNeedPage());
        }
        needPdmMapper.deleteByNeedId(need.getId());

        if (need.getNeedPdm() != null && need.getNeedPdm().size() != 0) {
            for (NeedPdm needPdm : need.getNeedPdm()) {
                needPdm.setNeedId(need.getId());
            }
            needPdmMapper.insertByBatch(need.getNeedPdm());
        }
        if (oldNeed.getAdmissibilityTime() == null && ("ACCEPT".equals(need.getStatus()) || "CONFIRM".equals(need.getStatus()))) {
            Map map = new HashMap();
            map.put("day", overtimeDay);
            map.put("admissibilityStatus", "NO_ACCEPT");
            map.put("id", need.getId());
            String acNeed = needMapper.getAcceptId(map);
            if (acNeed != null) {
                need.setAdmissibilityStatus("TIMELY");
            }
            need.setAdmissibilityTime(new Date());
        }


        //删除issue
        if ("FALLBACK".equals(need.getStatus()) || "1".equals(need.getIsFallback())) {
            need.setStatus("CLOSED");
            List<Issue> issues = issueManager.findByNeedId(need.getId());
            if (issues != null) {
                int issueCount = 0;
                for (Issue issue : issues) {
                    if (issue.getReqCount() != 0) {
                        issueCount++;
                        break;
                    }
                }
                if (issueCount == 0) {
                    for (Issue issue : issues) {
                        issueManager.deleteIssue(issue.getId());
                    }
                } else {
                    log.error("用户故事关联产品设计，禁止回退");
                    executeResult.setCode(BaseController.REQUEST_ERROR);
                    executeResult.setDesc("用户故事关联产品设计，禁止回退");
                    return executeResult;
                }
            }
        }
        if ("NO_ACCEPT".equals(need.getStatus())) {
            need.setAcceptAccount(null);
            need.setAcceptName(null);
        }
        if(need.getExpectLowerCostList().size()==0&&(!"ACCEPT".equals(need.getStatus()))){
            need.setExpectLowerCost("");
        }
        needMapper.updateByPrimaryKeySelective(need);
        executeResult.setData(need);
        return executeResult;
    }

    @Override
    public ExecuteResult<List<Need>> getNeedList(String id, Boolean isPage, String status, String proposerAccount, String source, String keyword, String pdmAccount, String pdmGroup, Long startDate, Boolean isOnline, String acceptAccount, String appointAcceptAccount, String myAccount) {
        ExecuteResult<List<Need>> executeResult = new ExecuteResult();
        if (isPage == null) {
            isPage = false;
        }
        if (isOnline == null) {
            isOnline = false;
        }
        String sdate = null;
        if (startDate != null) {
            sdate = DateGenerator.getYYYY_MM_DD(startDate);
        }
        Map map = new HashMap<String, Object>();
        map.put("id", id);
        map.put("status", status);
        map.put("proposerAccount", proposerAccount);
        map.put("source", source);
        map.put("keyword", keyword);
        map.put("pdmAccount", pdmAccount);
        map.put("pdmGroup", pdmGroup);
        map.put("sdate", sdate);
        map.put("isOnline", isOnline);
        map.put("acceptAccount", acceptAccount);
        map.put("appointAcceptAccount", appointAcceptAccount);
        map.put("myAccount", myAccount);
        List<Need> needs = needMapper.getNeedList(map);
        for (Need need : needs) {
            if (isPage) {
                need.setNeedPage(needPageMapper.getByNeedId(need.getId()));
            }
            need.setNeedPdm(needPdmMapper.getByNeedId(need.getId()));
            if (StringUtils.isNoneEmpty(id)) {
                need.setIssues(issueManager.findByNeedId(id));
            }
        }

        executeResult.setData(needs);
        return executeResult;
    }

    @Override
    public ExecuteResult updateNeedStar(String id, String star) {
        ExecuteResult er = new ExecuteResult();
        Need need = needMapper.selectByPrimaryKey(id);
        if (null == need) {
            log.error("com.winit.need.service.impl.NeedServiceImpl.updateNeedStar 没有找到需求 id=" + id);
            er.setCode(BaseController.REQUEST_ERROR);
            er.setDesc("没有找到id为" + id + "的需求");
            return er;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", id);
        map.put("star", star);
        map.put("status", "CLOSED");
        map.put("starType", "USER");
        map.put("statusTimes", NeedUtil.dealStatusTime(need.getStatusTimes(), "CLOSED"));
        needMapper.updateNeedStar(map);
        er.setData(map);
        return er;
    }

    @Override
    public void timingUpdate() {
        log.info("定时更新未受理状态需求");
        HashMap map = new HashMap();
        map.put("admissibilityStatus", "NO_ACCEPT");
        map.put("day", overtimeDay);
        List<String> ids = needMapper.getNoAcceptId(map);
        log.info("未受理状态需求数：" + ids.size());
        for (String id : ids) {
            Need need = new Need();
            need.setId(id);
            need.setAdmissibilityStatus("NOT_TIMELY");
            needMapper.updateByPrimaryKeySelective(need);
        }
    }

    @Override
    public void timingUpdateClosed() {
        log.info("定时更新上线状态改为结束并且评星");
        HashMap map = new HashMap();
        map.put("status", "ONLINE");
        List<Need> needs = needMapper.getNeedList(map);
        log.info("定时更新上线状态改为结束并且评星数：" + needs.size());
        for (Need need : needs) {
            need.setStatus("CLOSED");
            need.setStar("3");
            need.setStarType("SYS");
            need.setStatusTimes(NeedUtil.dealStatusTime(need.getStatusTimes(), "CLOSED"));
            needMapper.updateByPrimaryKeySelective(need);
        }
    }

    @Override
    public ExecuteResult<List> getNeedPlan(String needId) {
        ExecuteResult<List> er = new ExecuteResult<>();
        ArrayList<ProjectPlan> projectPlans = new ArrayList<>();
        List<Issue> issues = issueManager.findByNeedId(needId);
        Set<String> projectPlanIds = new HashSet<>();
        for (Issue issue : issues) {

            List<BrdRequirement> brdRequirements = brdRequirementManager.getIssueIdBrdRequirement(issue.getId());
            if (brdRequirements.size() > 0) {
                for (BrdRequirement brdRequirement : brdRequirements) {
                    if (brdRequirement.getProjectPlanId() != null) {
                        projectPlanIds.add(brdRequirement.getProjectPlanId());
                    }
                }
            }
        }
        if (projectPlanIds.size() == 0) {
            return er;
        }
        for (String planId : projectPlanIds) {
            projectPlans.add(projectPlanRepository.findOne(planId));
        }
        er.setData(projectPlans);
        return er;
    }

    @Override
    public ExecuteResult<Map<String, Long>> getStatusCount(JSONArray arr, Long starDate, Long endDate, String proposerAccount, String proposerDepartment, String productGroup, String pdmAccount, String source) {
        ExecuteResult<Map<String, Long>> executeResult = new ExecuteResult();
        String sdate = null;
        String edate = null;
        Map<String, Object> selectMap = new HashMap<>();
        if (starDate != null && endDate != null) {
            sdate = DateGenerator.getYYYY_MM_DD(starDate);
            edate = DateGenerator.getYYYY_MM_DD(endDate);
        }
        selectMap.put("sdate", sdate);
        selectMap.put("edate", edate);
        selectMap.put("proposerAccount", proposerAccount);
        selectMap.put("proposerDepartment", proposerDepartment);
        selectMap.put("productGroup", productGroup);
        selectMap.put("pdmAccount", pdmAccount);
        selectMap.put("source", source);

        Map map = new HashMap<String, Long>();
        for (int i = 0; i < arr.size(); i++) {
            map.put(arr.getString(i), 0);

        }
        List<Map> list = needMapper.getStatusCount(selectMap);
        for (Map cmap : list) {
            map.put(cmap.get("status"), cmap.get("count"));
        }

        executeResult.setData(map);
        return executeResult;
    }


    @Override
    public ExecuteResult<Map<String, Long>> getAcceptanceProbability(String type, Long starDate, Long endDate, String proposerAccount, String proposerDepartment, String productGroup, String pdmAccount, String source) {
        ExecuteResult<Map<String, Long>> executeResult = new ExecuteResult();
        List<String> days = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String sdate = null;
        String edate = null;
        if (starDate != null && endDate != null) {
            sdate = sdf.format(new Date(starDate));
            edate = sdf.format(new Date(endDate));
            try {
                days = DateGenerator.findDates(sdf.parse(sdate), sdf.parse(edate));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        } else {
            days = DateGenerator.getFrontThirtyDays();

        }
        Map map = new TreeMap();
        Map<String, Object> selectMap = new HashMap<>();
        List<Map> acceptances = new ArrayList<>();
        selectMap.put("sdate", sdate);
        selectMap.put("edate", edate);
        selectMap.put("proposerAccount", proposerAccount);
        selectMap.put("proposerDepartment", proposerDepartment);
        selectMap.put("productGroup", productGroup);
        selectMap.put("pdmAccount", pdmAccount);
        selectMap.put("source", source);
        if ("ACCEPT".equals(type)) {
            selectMap.put("admissibilityStatus", "TIMELY");
            acceptances = needMapper.getAcceptancePro(selectMap);
        } else {
            acceptances = needMapper.getCompletePro(selectMap);
        }

        for (String day : days) {
            map.put(day, 0);
        }
        for (Map acceptance : acceptances) {
            map.put(acceptance.get("date"), acceptance.get("count"));
        }
        executeResult.setData(map);
        return executeResult;
    }


    /**
     * 删除需求
     *
     * @param id
     */
    @Override
    public ExecuteResult deleteNeed(String id) {
        ExecuteResult ex = new ExecuteResult();
        Need need = needMapper.selectByPrimaryKey(id);
        if (need == null) {
            return ex;
        }
        needMapper.deleteByPrimaryKey(id);
        return ex;
    }

    @Override
    public ExecuteResult getAcceptAccountAndStatus(String acceptAccount, String status) {
        ExecuteResult executeResult = new ExecuteResult();
        Map map = new HashMap<>();
        map.put("acceptAccount", acceptAccount);
        map.put("status", status);
        List<Need> needList = needMapper.getAcceptAccountAndStatus(map);
        executeResult.setData(needList);
        return executeResult;
    }

    /**
     * 发送消息
     *
     * @param newNeed
     * @param oldNeed
     */
    private void sendNeedMsg(Need newNeed, Need oldNeed) {
        if (newNeed.getStatus() == null) {
            return;
        }
        switch (newNeed.getStatus()) {
            case "ACCEPT":
                log.info(oldNeed.getTitle() + ":需求确认状态");
                if ("ACCEPT".equals(oldNeed.getStatus())) {
                    log.info(oldNeed.getTitle() + ":二次需求确认状态");
                }
                break;
            case "FALLBACK":
                log.info(oldNeed.getTitle() + ":需求回退状态" + newNeed.getFallbackReason());
                break;
            case "CONFIRM":
                log.info(oldNeed.getTitle() + ":需求确认");
                sendEmailToNeedUsers(oldNeed, "需求[" + oldNeed.getTitle() + "]已经确认", "");
                break;
            case "ONLINE":
                log.info(oldNeed.getTitle() + ":需求上线");
                sendEmailToNeedUsers(oldNeed, "需求[" + oldNeed.getTitle() + "]已上线", "");
                break;
            default:
                break;
        }

    }

    /**
     * 给需求相关人员发邮件
     *
     * @param need    需求
     * @param subject 邮件主题
     * @param body    邮件内容
     */
    public void sendEmailToNeedUsers(Need need, String subject, String body) {
        StringBuffer to = new StringBuffer();
        try {
            if (StringUtils.isNotEmpty(need.getCreaterAccount())) {
                to.append(",").append(SendEmail.getEmailAddr(need.getCreaterAccount()));
            }
            if (StringUtils.isNotEmpty(need.getProposerAccount())) {
                to.append(",").append(SendEmail.getEmailAddr(need.getProposerAccount()));
            }
            if (StringUtils.isNotEmpty(need.getFollowAccount())) {
                to.append(",").append(SendEmail.getEmailAddr(need.getFollowAccount()));
            }
            if (StringUtils.isNotEmpty(need.getAcceptAccount())) {
                to.append(",").append(SendEmail.getEmailAddr(need.getAcceptAccount()));
            }
            if (StringUtils.isNotEmpty(need.getDeptChargeAccount())) {
                to.append(",").append(SendEmail.getEmailAddr(need.getDeptChargeAccount()));
            }
            if(need.getNeedPdm() != null && need.getNeedPdm().size()>0){
                for (NeedPdm pdm : need.getNeedPdm()) {
                    to.append(",").append(SendEmail.getEmailAddr(pdm.getAccount()));
                }
            }

            SendEmail.sendMail(to.toString(), subject, body);
        } catch (Exception e) {
            log.error("com.winit.need.service.impl.NeedServiceImpl.sendEmailToNeedUsers 异常",e);
        }

    }


}
